﻿using EU.Core.AuthHelper;
using EU.Core.Common;
using EU.Core.Common.AppConfig;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Tokens;
using System.Security.Claims;
using System.Text;

namespace EU.Core.Extensions;

/// <summary>
/// 系统 授权服务 配置
/// </summary>
public static class AuthorizationSetup
{
    public static void AddAuthorizationSetup(this IServiceCollection services)
    {
        if (services == null) throw new ArgumentNullException(nameof(services));

        // 以下四种常见的授权方式。

        // 1、这个很简单，其他什么都不用做， 只需要在API层的controller上边，增加特性即可
        // [Authorize(Roles = "Admin,System")]


        // 2、这个和上边的异曲同工，好处就是不用在controller中，写多个 roles 。
        // 然后这么写 [Authorize(Policy = "Admin")]
        services.AddAuthorization(options =>
        {
            options.AddPolicy("Client", policy => policy.RequireRole("Client").Build());
            options.AddPolicy("Admin", policy => policy.RequireRole("Admin").Build());
            options.AddPolicy("SystemOrAdmin", policy => policy.RequireRole("Admin", "System"));
            options.AddPolicy("A_S_O", policy => policy.RequireRole("Admin", "System", "Others"));
        });




        #region 参数
        //读取配置文件
        var symmetricKeyAsBase64 = AppSecretConfig.Audience_Secret_String;
        var keyByteArray = Encoding.ASCII.GetBytes(symmetricKeyAsBase64);
        var signingKey = new SymmetricSecurityKey(keyByteArray);
        var Issuer = AppSettings.app(new string[] { "Audience", "Issuer" });
        var Audience = AppSettings.app(new string[] { "Audience", "Audience" });

        var signingCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256);

        // 如果要数据库动态绑定，这里先留个空，后边处理器里动态赋值
        var permission = new List<PermissionItem>();

        // 角色与接口的权限要求参数
        var permissionRequirement = new PermissionRequirement(
            "/api/denied",// 拒绝授权的跳转地址（目前无用）
            permission,
            ClaimTypes.Role,//基于角色的授权
            Issuer,//发行人
            Audience,//听众
            signingCredentials,//签名凭据
            expiration: TimeSpan.FromSeconds(240 * 60)//接口的过期时间
            );
        #endregion
        // 3、自定义复杂的策略授权
        services.AddAuthorization(options =>
        {
            options.AddPolicy(Permissions.Name,
                     policy => policy.Requirements.Add(permissionRequirement));
        });


        // 4、基于Scope策略授权
        //services.AddAuthorization(options =>
        //{
        //    options.AddPolicy("Scope_TiobonModule_Policy", builder =>
        //    {
        //        //客户端Scope中包含EU.core.api.TiobonModule才能访问
        //        // 同时引用nuget包：IdentityServer4.AccessTokenValidation
        //        builder.RequireScope("EU.core.api.TiobonModule");
        //    });

        //    // 其他 Scope 策略
        //    // ...

        //});

        // 这里冗余写了一次,因为很多人看不到
        services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
        // 注入权限处理器
        services.AddScoped<IAuthorizationHandler, PermissionHandler>();
        services.AddSingleton(permissionRequirement);
    }
}
